﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsFormsApplication1
{
    public  class QrsFilt
    {

        private static int lpY1, lpY2;
    	private static int[] lpData;
  	  	private static int lpPtr;
   	 	private static long hpY = 0;
    	private static int[] hpData;
    	private static int hpPtr = 0;

    	private static int der1 = 0;

    	private static int der2 = 0;
    	private static int mvWintSum = 0;
    	private static int[] mvWintData;
    	private static int mvWintPtr = 0;
    	private static int[] der1Buff;
    	private static int[] der2Buff;
      
		public  QrsFilt()
        {
            der1Buff = new int[SampleRates.windowWidth];
            der2Buff = new int[SampleRates.derivLength];
                hpfilt(0, 1); 
                lpfilt(0, 1);
                mvwint(0, 1);
                deriv1(0, 1);
                deriv2(0, 1);
          
        }

        public int filter(int datum)
        {
            int fdatum;
            fdatum = lpfilt(datum, 0);  // Low pass filter data.
            fdatum = hpfilt(fdatum, 0); // High pass filter data.
            fdatum = deriv2(fdatum, 0); // Take the derivative.
            fdatum = Math.Abs(fdatum);  // Take the absolute value.
            fdatum = mvwint(fdatum, 0); // Average over an 80 ms window .
            return (fdatum);
        }


        /*****************************************************************************
        *  Filtro Passa Baixa:
        *
        * 	y[n] = 2*y[n-1] - y[n-2] + x[n] - 2*x[t-24 ms] + x[t-48 ms]
        	*******************************************************************************/

        public  int lpfilt(int datum, int init)
        {
            
            int y0;
            int output, halfPtr;

            if (init != 0)
            {
				lpData = new int[SampleRates.lpBufferLgth];
                for (lpPtr = 0; lpPtr < SampleRates.lpBufferLgth; ++lpPtr)
                    lpData[lpPtr] = 0;
                lpY1 = lpY2 = 0;
                lpPtr = 0;
				return 0;
            }
			
            halfPtr = lpPtr - (SampleRates.lpBufferLgth / 2); 

            if (halfPtr < 0) 
                halfPtr += SampleRates.lpBufferLgth;

            y0 = (2*lpY1) - lpY2 + datum - (2*lpData[halfPtr] ) + lpData[lpPtr];
            lpY2 = lpY1;
            lpY1 = y0;
            output =  y0 / ((SampleRates.lpBufferLgth * SampleRates.lpBufferLgth) / 4);
            lpData[lpPtr] = datum; 

            if (++lpPtr == SampleRates.lpBufferLgth)
                lpPtr = 0; 

            return (output);
        }


        /*****************************************************************************
        * Filtro Passa Alta
        *
        *	y[n] = y[n-1] + x[n] - x[n-128 ms]
        *	z[n] = x[n-64 ms] - y[n] ;
     	       *****************************************************************************/

        public  int hpfilt(int datum, int init)
        {
            
            int z, halfPtr;

            if (init != 0)
            {
				hpData = new int[SampleRates.hpBufferLgth];
                for (hpPtr = 0; hpPtr < SampleRates.hpBufferLgth; ++hpPtr)
                    hpData[hpPtr] = 0;

                hpPtr = 0;
                hpY = 0;
				return 0;
            }

            hpY += datum - hpData[hpPtr];
            halfPtr = hpPtr - (SampleRates.hpBufferLgth / 2);
            if (halfPtr < 0)
                halfPtr += SampleRates.hpBufferLgth;

            z = hpData[halfPtr] - (int) (hpY /SampleRates.hpBufferLgth);
            hpData[hpPtr] = datum;

            if (++hpPtr == SampleRates.hpBufferLgth)
                hpPtr = 0;

            return (z);
        }


        /*****************************************************************************
        *  Derivativo
        *
        *	y[n] = x[n] - x[n - 10ms]
     		*****************************************************************************/

        public  int deriv1(int x, int init)
        {
            int y;

            if(init != 0)
            {
                for(der1 = 0; der1 < SampleRates.derivLength; ++der1)
                    der1Buff[der1] = 0 ;
                der1 = 0;

                return (0);
            }

            y = x - der1Buff[der1];
            der1Buff[der1] = x;

            if(++der1 == SampleRates.derivLength)
                der1 = 0;

            return (y);
        }

        public static int deriv2(int x, int init)
        {
             int y;

            if(init != 0)
            {
                for (der2 = 0; der2 < SampleRates.derivLength; ++der2)
                    der2Buff[der2] = 0;

                der2 = 0;
                return (0);
            }

            y = x - der2Buff[der2] ;
            der2Buff[der2] = x ;

            if(++der2 == SampleRates.derivLength)
                der2 = 0;

            return (y);
        }


        /*****************************************************************************
        * Integrador
        	*****************************************************************************/

        public  int mvwint(int datum, int init)
        {
            int output;

            if (init !=0)
            {
				mvWintData = new int[SampleRates.windowWidth];
                for(mvWintPtr = 0; mvWintPtr < SampleRates.windowWidth ; ++mvWintPtr)
                    mvWintData[mvWintPtr] = 0;
                mvWintSum = 0;
                mvWintPtr = 0;
				return 0 ;
            }
			
            mvWintSum += datum;
            mvWintSum -= mvWintData[mvWintPtr];
            mvWintData[mvWintPtr] = datum;

            if (++mvWintPtr == SampleRates.windowWidth)
                mvWintPtr = 0;

            if ((mvWintSum / SampleRates.windowWidth) > 32000)
                output = 32000;
            else
                output =  mvWintSum / SampleRates.windowWidth;
            return (output);
        }

    }
}
